home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 051-075 / disk_061 / microemacs / input.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  10KB  |  491 lines

  1. /*    INPUT:    Various input routines for MicroEMACS 3.7
  2.         written by Daniel Lawrence
  3.         5/9/86                        */
  4.  
  5. #include    <stdio.h>
  6. #include    "estruct.h"
  7. #include    "edef.h"
  8.  
  9. #if    MEGAMAX
  10. overlay "input"
  11. #endif
  12.  
  13. /*
  14.  * Ask a yes or no question in the message line. Return either TRUE, FALSE, or
  15.  * ABORT. The ABORT status is returned if the user bumps out of the question
  16.  * with a ^G. Used any time a confirmation is required.
  17.  */
  18.  
  19. mlyesno(prompt)
  20.  
  21. char *prompt;
  22.  
  23. {
  24.     char c;            /* input character */
  25.     char buf[NPAT];        /* prompt to user */
  26.  
  27.     for (;;) {
  28.         /* build and prompt the user */
  29.         strcpy(buf, prompt);
  30.         strcat(buf, " [y/n]? ");
  31.         mlwrite(buf);
  32.  
  33.         /* get the responce */
  34.         c = tgetc();
  35.  
  36.         if (c == ectoc(abortc))        /* Bail out! */
  37.             return(ABORT);
  38.  
  39.         if (c=='y' || c=='Y')
  40.             return(TRUE);
  41.  
  42.         if (c=='n' || c=='N')
  43.             return(FALSE);
  44.     }
  45. }
  46.  
  47. /*
  48.  * Write a prompt into the message line, then read back a response. Keep
  49.  * track of the physical position of the cursor. If we are in a keyboard
  50.  * macro throw the prompt away, and return the remembered response. This
  51.  * lets macros run at full speed. The reply is always terminated by a carriage
  52.  * return. Handle erase, kill, and abort keys.
  53.  */
  54.  
  55. mlreply(prompt, buf, nbuf)
  56.     char *prompt;
  57.     char *buf;
  58. {
  59.     return(nextarg(prompt, buf, nbuf, ctoec('\n')));
  60. }
  61.  
  62. mlreplyt(prompt, buf, nbuf, eolchar)
  63.  
  64. char *prompt;
  65. char *buf;
  66. int eolchar;
  67.  
  68. {
  69.     return(nextarg(prompt, buf, nbuf, eolchar));
  70. }
  71.  
  72. /*    ectoc:    expanded character to character
  73.         colapse the CTRL and SPEC flags back into an ascii code   */
  74.  
  75. ectoc(c)
  76.  
  77. int c;
  78.  
  79. {
  80.     if (c & CTRL)
  81.         c = c & ~(CTRL | 0x40);
  82.     if (c & SPEC)
  83.         c= c & 255;
  84.     return(c);
  85. }
  86.  
  87. /*    ctoec:    character to extended character
  88.         pull out the CTRL and SPEC prefixes (if possible)    */
  89.  
  90. ctoec(c)
  91.  
  92. int c;
  93.  
  94. {
  95.         if (c>=0x00 && c<=0x1F)
  96.                 c = CTRL | (c+'@');
  97.         return (c);
  98. }
  99.  
  100. /* get a command name from the command line. Command completion means
  101.    that pressing a <SPACE> will attempt to complete an unfinished command
  102.    name if it is unique.
  103. */
  104.  
  105. int (*getname())()
  106.  
  107. {
  108.     register int cpos;    /* current column on screen output */
  109.     register int c;
  110.     register char *sp;    /* pointer to string for output */
  111.     register NBIND *ffp;    /* first ptr to entry in name binding table */
  112.     register NBIND *cffp;    /* current ptr to entry in name binding table */
  113.     register NBIND *lffp;    /* last ptr to entry in name binding table */
  114.     char buf[NSTRING];    /* buffer to hold tentative command name */
  115.     int (*fncmatch())();
  116.  
  117.     /* starting at the beginning of the string buffer */
  118.     cpos = 0;
  119.  
  120.     /* if we are executing a command line get the next arg and match it */
  121.     if (clexec) {
  122.         if (macarg(buf) != TRUE)
  123.             return(FALSE);
  124.         return(fncmatch(&buf[0]));
  125.     }
  126.  
  127.     /* build a name string from the keyboard */
  128.     while (TRUE) {
  129.         c = tgetc();
  130.  
  131.         /* if we are at the end, just match it */
  132.         if (c == 0x0d) {
  133.             buf[cpos] = 0;
  134.  
  135.             /* and match it off */
  136.             return(fncmatch(&buf[0]));
  137.  
  138.         } else if (c == ectoc(abortc)) {    /* Bell, abort */
  139.             ctrlg(FALSE, 0);
  140.             TTflush();
  141.             return( (int (*)()) NULL);
  142.  
  143.         } else if (c == 0x7F || c == 0x08) {    /* rubout/erase */
  144.             if (cpos != 0) {
  145.                 TTputc('\b');
  146.                 TTputc(' ');
  147.                 TTputc('\b');
  148.                 --ttcol;
  149.                 --cpos;
  150.                 TTflush();
  151.             }
  152.  
  153.         } else if (c == 0x15) {    /* C-U, kill */
  154.             while (cpos != 0) {
  155.                 TTputc('\b');
  156.                 TTputc(' ');
  157.                 TTputc('\b');
  158.                 --cpos;
  159.                 --ttcol;
  160.             }
  161.  
  162.             TTflush();
  163.  
  164.         } else if (c == ' ') {
  165. /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
  166.     /* attempt a completion */
  167.     buf[cpos] = 0;        /* terminate it for us */
  168.     ffp = &names[0];    /* scan for matches */
  169.     while (ffp->n_func != NULL) {
  170.         if (strncmp(buf, ffp->n_name, strlen(buf)) == 0) {
  171.             /* a possible match! More than one? */
  172.             if ((ffp + 1)->n_func == NULL ||
  173.                (strncmp(buf, (ffp+1)->n_name, strlen(buf)) != 0)) {
  174.                 /* no...we match, print it */
  175.                 sp = ffp->n_name + cpos;
  176.                 while (*sp)
  177.                     TTputc(*sp++);
  178.                 TTflush();
  179.                 return(ffp->n_func);
  180.             } else {
  181. /* << << << << << << << << << << << << << << << << << */
  182.     /* try for a partial match against the list */
  183.  
  184.     /* first scan down until we no longer match the current input */
  185.     lffp = (ffp + 1);
  186.     while ((lffp+1)->n_func != NULL) {
  187.         if (strncmp(buf, (lffp+1)->n_name, strlen(buf)) != 0)
  188.             break;
  189.         ++lffp;
  190.     }
  191.  
  192.     /* and now, attempt to partial complete the string, char at a time */
  193.     while (TRUE) {
  194.         /* add the next char in */
  195.         buf[cpos] = ffp->n_name[cpos];
  196.  
  197.         /* scan through the candidates */
  198.         cffp = ffp + 1;
  199.         while (cffp <= lffp) {
  200.             if (cffp->n_name[cpos] != buf[cpos])
  201.                 goto onward;
  202.             ++cffp;
  203.         }
  204.  
  205.         /* add the character */
  206.         TTputc(buf[cpos++]);
  207.     }
  208. /* << << << << << << << << << << << << << << << << << */
  209.             }
  210.         }
  211.         ++ffp;
  212.     }
  213.  
  214.     /* no match.....beep and onward */
  215.     TTbeep();
  216. onward:;
  217.     TTflush();
  218. /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
  219.         } else {
  220.             if (cpos < NSTRING-1 && c > ' ') {
  221.                 buf[cpos++] = c;
  222.                 TTputc(c);
  223.             }
  224.  
  225.             ++ttcol;
  226.             TTflush();
  227.         }
  228.     }
  229. }
  230.  
  231. /*    tgetc:    Get a key from the terminal driver, resolve any keyboard
  232.         macro action                    */
  233.  
  234. int tgetc()
  235.  
  236. {
  237.     int c;    /* fetched character */
  238.  
  239.     /* if we are playing a keyboard macro back, */
  240.     if (kbdmode == PLAY) {
  241.  
  242.         /* if there is some left... */
  243.         if (kbdptr < kbdend)
  244.             return((int)*kbdptr++);
  245.  
  246.         /* at the end of last repitition? */
  247.         if (--kbdrep < 1) {
  248.             kbdmode = STOP;
  249. #if    VISMAC == 0
  250.             /* force a screen update after all is done */
  251.             update(FALSE);
  252. #endif
  253.         } else {
  254.  
  255.             /* reset the macro to the begining for the next rep */
  256.             kbdptr = &kbdm[0];
  257.             return((int)*kbdptr++);
  258.         }
  259.     }
  260.  
  261.     /* fetch a character from the terminal driver */
  262.     c = TTgetc();
  263.  
  264.     /* save it if we need to */
  265.     if (kbdmode == RECORD) {
  266.         *kbdptr++ = c;
  267.         kbdend = kbdptr;
  268.  
  269.         /* don't overrun the buffer */
  270.         if (kbdptr == &kbdm[NKBDM - 1]) {
  271.             kbdmode = STOP;
  272.             TTbeep();
  273.         }
  274.     }
  275.  
  276.     /* and finally give the char back */
  277.     return(c);
  278. }
  279.  
  280. /*    GET1KEY:    Get one keystroke. The only prefixs legal here
  281.             are the SPEC and CTRL prefixes.
  282.                                 */
  283.  
  284. get1key()
  285.  
  286. {
  287.     int    c;
  288. #if    AMIGA
  289.     int    d;
  290. #endif
  291.  
  292.     /* get a keystroke */
  293.         c = tgetc();
  294.  
  295. #if    MSDOS
  296.     if (c == 0) {                /* Apply SPEC prefix    */
  297.             c = tgetc();
  298.             if (c>=0x00 && c<=0x1F)        /* control key? */
  299.                     c = CTRL | (c+'@');
  300.         return(SPEC | c);
  301.     }
  302. #endif
  303.  
  304. #if    AMIGA
  305.     /* apply SPEC prefix */
  306.     if ((unsigned)c == 155) {
  307.         c = tgetc();
  308.  
  309.         /* first try to see if it is a cursor key */
  310.         if ((c >= 'A' && c <= 'D') || c == 'S' || c == 'T')
  311.             return(SPEC | c);
  312.  
  313.         /* next, a 2 char sequence */
  314.         d = tgetc();
  315.         if (d == '~')
  316.             return(SPEC | c);
  317.  
  318.         /* decode a 3 char sequence */
  319.         c = d + 32;
  320.         /* if a shifted function key, eat the tilde */
  321.         if (d >= '0' && d <= '9')
  322.             d = tgetc();
  323.         return(SPEC | c);
  324.     }
  325. #endif
  326.  
  327. #if  WANGPC
  328.     if (c == 0x1F) {            /* Apply SPEC prefix    */
  329.             c = tgetc();
  330.         return(SPEC | c);
  331.     }
  332. #endif
  333.  
  334.         if (c>=0x00 && c<=0x1F)                 /* C0 control -> C-     */
  335.                 c = CTRL | (c+'@');
  336.         return (c);
  337. }
  338.  
  339. /*    GETCMD:    Get a command from the keyboard. Process all applicable
  340.         prefix keys
  341.                             */
  342. getcmd()
  343.  
  344. {
  345.     int c;        /* fetched keystroke */
  346.  
  347.     /* get initial character */
  348.     c = get1key();
  349.  
  350.     /* process META prefix */
  351.     if (c == metac) {
  352.         c = get1key();
  353.             if (islower(c))        /* Force to upper */
  354.                     c ^= DIFCASE;
  355.             if (c>=0x00 && c<=0x1F)        /* control key */
  356.                 c = CTRL | (c+'@');
  357.         return(META | c);
  358.     }
  359.  
  360.     /* process CTLX prefix */
  361.     if (c == ctlxc) {
  362.         c = get1key();
  363.             if (c>='a' && c<='z')        /* Force to upper */
  364.                     c -= 0x20;
  365.             if (c>=0x00 && c<=0x1F)        /* control key */
  366.                 c = CTRL | (c+'@');
  367.         return(CTLX | c);
  368.     }
  369.  
  370.     /* otherwise, just return it */
  371.     return(c);
  372. }
  373.  
  374. /*    A more generalized prompt/reply function allowing the caller
  375.     to specify the proper terminator. If the terminator is not
  376.     a return ('\n') it will echo as "<NL>"
  377.                             */
  378. getstring(prompt, buf, nbuf, eolchar)
  379.  
  380. char *prompt;
  381. char *buf;
  382. int eolchar;
  383.  
  384. {
  385.     register int cpos;    /* current character position in string */
  386.     register int c;
  387.     register int quotef;    /* are we quoting the next char? */
  388.  
  389.     cpos = 0;
  390.     quotef = FALSE;
  391.  
  392.     /* prompt the user for the input string */
  393.     mlwrite(prompt);
  394.  
  395.     for (;;) {
  396.         /* get a character from the user */
  397.         c = get1key();
  398.  
  399.         /* If it is a <ret>, change it to a <NL> */
  400.         if (c == (CTRL | 0x4d))
  401.             c = CTRL | 0x40 | '\n';
  402.  
  403.         /* if they hit the line terminate, wrap it up */
  404.         if (c == eolchar && quotef == FALSE) {
  405.             buf[cpos++] = 0;
  406.  
  407.             /* clear the message line */
  408.             mlwrite("");
  409.             TTflush();
  410.  
  411.             /* if we default the buffer, return FALSE */
  412.             if (buf[0] == 0)
  413.                 return(FALSE);
  414.  
  415.             return(TRUE);
  416.         }
  417.  
  418.         /* change from command form back to character form */
  419.         c = ectoc(c);
  420.  
  421.         if (c == ectoc(abortc) && quotef == FALSE) {
  422.             /* Abort the input? */
  423.             ctrlg(FALSE, 0);
  424.             TTflush();
  425.             return(ABORT);
  426.         } else if ((c==0x7F || c==0x08) && quotef==FALSE) {
  427.             /* rubout/erase */
  428.             if (cpos != 0) {
  429.                 outstring("\b \b");
  430.                 --ttcol;
  431.  
  432.                 if (buf[--cpos] < 0x20) {
  433.                     outstring("\b \b");
  434.                     --ttcol;
  435.                 }
  436.  
  437.                 if (buf[cpos] == '\n') {
  438.                     outstring("\b\b  \b\b");
  439.                     ttcol -= 2;
  440.                 }
  441.                 TTflush();
  442.             }
  443.  
  444.         } else if (c == 0x15 && quotef == FALSE) {
  445.             /* C-U, kill */
  446.             while (cpos != 0) {
  447.                 outstring("\b \b");
  448.                 --ttcol;
  449.  
  450.                 if (buf[--cpos] < 0x20) {
  451.                     outstring("\b \b");
  452.                     --ttcol;
  453.                 }
  454.             }
  455.             TTflush();
  456.  
  457.         } else if (c == quotec && quotef == FALSE) {
  458.             quotef = TRUE;
  459.         } else {
  460.             quotef = FALSE;
  461.             if (cpos < nbuf-1) {
  462.                 buf[cpos++] = c;
  463.  
  464.                 if ((c < ' ') && (c != '\n')) {
  465.                     outstring("^");
  466.                     ++ttcol;
  467.                     c ^= 0x40;
  468.                 }
  469.  
  470.                 if (c != '\n')
  471.                     TTputc(c);
  472.                 else {    /* put out <NL> for <ret> */
  473.                     outstring("<NL>");
  474.                     ttcol += 3;
  475.                 }
  476.                 ++ttcol;
  477.                 TTflush();
  478.             }
  479.         }
  480.     }
  481. }
  482.  
  483. outstring(s)    /* output a string of characters */
  484.  
  485. char *s;    /* string to output */
  486.  
  487. {
  488.     while (*s)
  489.         TTputc(*s++);
  490. }
  491.